﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Jayden.Dll.Cards.Poker.Enums;
using System.Threading;

namespace Jayden.Dll.Cards.Poker
{
	public class TexasHoldemDealer : PokerDealer
	{
		private CardList m_Deck;
		private ulong m_HandCount;
		private bool m_Busy = false;
		private CardList m_CommunityCards = new CardList();
		private CardList[] m_ClosedCards = new CardList[9];
		private ulong[] m_Bets = new ulong[9];
		private byte m_CurrentAction = 0xff;
		private bool m_FirstHand = true;
		private List<PokerTableSeat> m_PlayersLeftToTalk = new List<PokerTableSeat>();

		public ulong HandCount { get { return m_HandCount; } }
		public CardList CommunityCards { get { return m_CommunityCards; } }
		public CardList[] CloseCards { get { return m_ClosedCards; } }
		public ulong[] Bets { get { return m_Bets; } }
		public byte CurrentAction { get { return m_CurrentAction; } }
		public HashSet<Card> Visible = new HashSet<Card>();
		public List<PokerTableSeat> PlayersLeftToTalk { get { return m_PlayersLeftToTalk; } }

		public override bool Busy { get { return m_Busy; } }

		public override bool CanDeal(PokerGameConfiguration config)
		{
			if (config.Limit == PokerLimit.NoLimit && config.Type == PokerType.TexasHoldem)
				return true;
			return false;
		}

		protected List<PokerTableSeat> ResetOrder(List<PokerTableSeat> players, List<PokerTableSeat> order)
		{
			List<PokerTableSeat> results = new List<PokerTableSeat>();
			foreach (PokerTableSeat player in order)
				if (players.Contains(player))
					results.Add(player);
			return results;
		}

		public override int FirstIdlePlayerIndex
		{
			get
			{
				foreach (PokerTableSeat seat in Table.OccupiedSeats)
					if (m_ClosedCards[seat.Index] == null)
						return seat.Index;
				return -1;
			}
		}

		public override void NextHand()
		{
			if (m_Busy)
				throw new Exception("dealer is already busy.");
			m_Busy = true;
			List<PokerTableSeat> seats = new List<PokerTableSeat>(Table.OccupiedSeats);
			if (seats.Count < 2)
				throw new Exception("Not enough players seated.");
			List<PokerTableSeat> playingSeats = new List<PokerTableSeat>();
			List<PokerTableSeat> forcedPost = new List<PokerTableSeat>();
			bool first = true;
			foreach (PokerTableSeat player in seats)
			{
				if (player.State == PokerSeatState.Waiting && player.Stack > 0)
				{
					player.State = PokerSeatState.Playing;
					if (!m_FirstHand)
					{
						if (Configuration.IsCashGame)
						{
							if (player.Index != Table.Button || seats.Count == 2)
							{
								if (playingSeats.Count != 1)
								{
									if (seats.Count == 2 || GetForcedPost(player, first, 5000))
										forcedPost.Add(player);
									else
										player.State = PokerSeatState.Waiting;
								}
							}
							else // cannot enter as button
								player.State = PokerSeatState.Waiting;
						}
						else if (Configuration.IsTournament)
						{
							if (first || player.Index == Table.Button) // cannot enter as smallblind or button
								player.State = PokerSeatState.Waiting;
						}
					}
				}
				if ((player.State == PokerSeatState.Playing || (player.State == PokerSeatState.SittingOut && Configuration.IsTournament)) && player.Stack > 0)
				{
					playingSeats.Add(player);
					first = false;
				}
				if (player.State == PokerSeatState.Disconnected)
				{
					if (Configuration.IsCashGame)
					{
						string login = player.Player.Login;
						player.Player.BankRoll += player.Stack;
						player.Player = null;
						player.Stack = 0;
						player.State = PokerSeatState.Empty;
						Table.BroadCastMessage(string.Format("{0}: leaving", login));
					}
					else
						Thread.Sleep(1000);
				}
			}
			if (playingSeats.Count < 2)
			{
				Thread.Sleep(1000);
				return;
			}

			int nextDealer = playingSeats[0].Index;

			m_HandCount++;
			// create a new deck and shuffle it
			m_Deck = CardList.New52CardsDeck();
			m_Deck.Shuffle();

			m_Pot = new PokerPot();
			m_HandDateTime = DateTime.Now;
			string message = "Starting hand #{0} {1} {2} ({3} {5}/{6} with ante {4}) Button is on seat {7}.";
			if(Ante == 0)
				message = "Starting hand #{0} {1} {2} ({3} {5}/{6}) Button is on seat {7}.";
			m_Street = PokerStreetType.PreFlop;
			Table.BroadCastMessage(string.Format(message, m_HandCount, Type, Limit, Currency, Currency.ToString(Ante, false), Currency.ToString(SmallBlind, false), Currency.ToString(BigBlind, false), Table.Button));
			List<PokerTableSeat> playersLeft = new List<PokerTableSeat>(playingSeats);
			if (Ante > 0)
			{
				foreach (PokerTableSeat seat in playersLeft)
				{
					ulong amount = Math.Min(Ante, seat.Stack);
					seat.Stack -= amount;
					m_Pot.Add(seat.Player.Login, amount);
					Table.BroadCastMessage(string.Format("{0}: posts the ante {1}", seat.Player.Login, Currency.ToString(amount)));
					Table.BroadCastAction(seat.Player.Login, PokerActionType.Ante, amount);
					Thread.Sleep(300);
				}
			}
			PokerTableSeat smallSeat = playersLeft[playingSeats.Count == 2 ? 1 : 0];
			PokerTableSeat bigSeat = playersLeft[playingSeats.Count == 2 ? 0 : 1];
			ulong smallBlind = Math.Min(SmallBlind, smallSeat.Stack);
			ulong bigBlind = Math.Min(BigBlind, bigSeat.Stack);
			playersLeft.Remove(smallSeat);
			playersLeft.Add(smallSeat);
			playersLeft.Remove(bigSeat);
			playersLeft.Add(bigSeat);
			smallSeat.Stack -= smallBlind;
			m_Pot.Add(smallSeat.Player.Login, smallBlind);
			m_Bets[smallSeat.Index] += smallBlind;
			Table.BroadCastMessage(string.Format("{0}: posts small blind {1}", smallSeat.Player.Login, Currency.ToString(smallBlind)));
			Table.BroadCastAction(smallSeat.Player.Login, PokerActionType.SmallBlind, smallBlind);
			Thread.Sleep(500);
			bigSeat.Stack -= bigBlind;
			m_Pot.Add(bigSeat.Player.Login, bigBlind);
			m_Bets[bigSeat.Index] += bigBlind;
			Table.BroadCastMessage(string.Format("{0}: posts big blind {1}", bigSeat.Player.Login, Currency.ToString(bigBlind)));
			Table.BroadCastAction(bigSeat.Player.Login, PokerActionType.BigBlind, bigBlind);
			Thread.Sleep(500);

			foreach (PokerTableSeat forced in forcedPost)
			{
				if (forced == smallSeat)
				{
					forced.Stack -= bigBlind;
					m_Pot.Add(forced.Player.Login, bigBlind - smallBlind);
					Pot.Add("__dead_small__\t" + forced.Player.Login, smallBlind);
					m_Bets[forced.Index] += bigBlind - smallBlind;
					Table.BroadCastMessage(string.Format("{0} buy the button ({1}) to enter the game.", forced.Player.Login, Currency.ToString(bigBlind)));
					Table.BroadCastAction(forced.Player.Login, PokerActionType.BigBlind, bigBlind);
				}
				else if (forced != bigSeat)
				{
					forced.Stack -= bigBlind;
					m_Pot.Add(forced.Player.Login, bigBlind);
					m_Bets[forced.Index] += bigBlind;
					Table.BroadCastMessage(string.Format("{0} pay forced big blind ({1}) to enter the game.", forced.Player.Login, Currency.ToString(bigBlind)));
					Table.BroadCastAction(forced.Player.Login, PokerActionType.BigBlind, bigBlind);
				}
			}

			foreach (PokerTableSeat seat in playingSeats)
			{
				m_ClosedCards[seat.Index] = new CardList();
				m_ClosedCards[seat.Index].Add(m_Deck.Pop());
			}
			foreach (PokerTableSeat seat in playingSeats)
			{
				m_ClosedCards[seat.Index].Add(m_Deck.Pop());
				seat.Player.SendCloseCards(Table, m_ClosedCards[seat.Index]);
			}
			bool allIn = false;
			playersLeft = NextActions(playersLeft, out allIn);
			for (int c = 0; c < m_Bets.Length; c++)
				m_Bets[c] = 0;
			playersLeft = ResetOrder(playersLeft, playingSeats);

			if (playersLeft.Count > 1)
			{

				if (playingSeats.Count == 2)
				{
					playersLeft.Clear();
					playersLeft.Add(bigSeat);
					playersLeft.Add(smallSeat);
				}

				// flop
				m_Deck.Burn();
				m_CommunityCards.Add(m_Deck.Pop());
				m_CommunityCards.Add(m_Deck.Pop());
				m_CommunityCards.Add(m_Deck.Pop());
				m_Street = PokerStreetType.Flop;
				Table.ShowCards(m_CommunityCards[0], m_CommunityCards[1], m_CommunityCards[2]);
				Table.BroadCastMessage(string.Format("*** FLOP *** [{0}]", m_CommunityCards.ToString()));
				if(allIn)
					Thread.Sleep(2000);
				else
					Thread.Sleep(300);
				playersLeft = NextActions(playersLeft, out allIn);
				for (int c = 0; c < m_Bets.Length; c++)
					m_Bets[c] = 0;
				playersLeft = ResetOrder(playersLeft, playingSeats);

				if (playersLeft.Count > 1)
				{
					playersLeft = ResetOrder(playersLeft, playingSeats);
					// turn
					m_Deck.Burn();
					CardList cards = new CardList(m_CommunityCards);
					m_CommunityCards.Add(m_Deck.Pop());
					m_Street = PokerStreetType.Turn;
					Table.ShowCards(m_CommunityCards[3]);
					Table.BroadCastMessage(string.Format("*** TURN *** [{0}] [{1}]", cards.ToString(), m_CommunityCards[m_CommunityCards.Count - 1].ToShortString()));
					if (allIn)
						Thread.Sleep(2000);
					else
						Thread.Sleep(300);
					playersLeft = NextActions(playersLeft, out allIn);
					for (int c = 0; c < m_Bets.Length; c++)
						m_Bets[c] = 0;
					playersLeft = ResetOrder(playersLeft, playingSeats);

					if (playersLeft.Count > 1)
					{
						// river
						m_Deck.Burn();
						cards = new CardList(m_CommunityCards);
						m_CommunityCards.Add(m_Deck.Pop());
						m_Street = PokerStreetType.River;
						Table.ShowCards(m_CommunityCards[4]);
						Table.BroadCastMessage(string.Format("*** RIVER *** [{0}] [{1}]", cards.ToString(), m_CommunityCards[m_CommunityCards.Count - 1].ToShortString()));
						if (allIn)
							Thread.Sleep(2000);
						else
							Thread.Sleep(300);
						playersLeft = NextActions(playersLeft, out allIn);
						for (int c = 0; c < m_Bets.Length; c++)
							m_Bets[c] = 0;
						// if there is aggression on the river, the last betting/raising player have to show his cards first
						//playersLeft = ResetOrder(playersLeft, playingSeats);
					}
				}
			}
			m_Street = PokerStreetType.Showdown;
			m_CurrentAction = 0xff;
			if (playersLeft.Count > 1)
			{
				Table.BroadCastMessage(string.Format("*** SHOWDOWN ***"));
				CardSet communitySet = new CardSet(m_CommunityCards);
				Dictionary<string, CardSet> players = new Dictionary<string, CardSet>();

				PokerHighHand[] hands = new PokerHighHand[Table.NumberOfSeats];
				PokerHighHand bestHand = null;
				ulong mostMoney = 0;
				playersLeft = OrderForShowdown(playersLeft);
				foreach (PokerTableSeat seat in playersLeft)
				{
					m_CurrentAction = (byte)seat.Index;
					CardSet set = new CardSet(m_ClosedCards[seat.Index]);
					players.Add(seat.Player.Login, set);
					hands[seat.Index] = PokerHighHand.GetBestHand(new CardSet(set, communitySet));
					ulong amount = m_Pot.GetTotalAmountForPlayer(seat.Player.Login);
					if (amount > mostMoney || bestHand == null || hands[seat.Index].CompareTo(bestHand) <= 0)
					{
						Visible.Add(m_ClosedCards[seat.Index][0]);
						Visible.Add(m_ClosedCards[seat.Index][1]);
						Table.BroadCastMessage(string.Format("{0}: shows [{1}] ({2})", seat.Player.Login, m_ClosedCards[seat.Index], hands[seat.Index].Description));
						bestHand = hands[seat.Index];
						if (mostMoney < amount)
							mostMoney = amount;
						Thread.Sleep(3000);
					}
					else
					{
						if (GetShowCards(seat, 2500))
						{
							Visible.Add(m_ClosedCards[seat.Index][0]);
							Visible.Add(m_ClosedCards[seat.Index][1]);
							Table.BroadCastMessage(string.Format("{0}: shows [{1}] ({2})", seat.Player.Login, m_ClosedCards[seat.Index], hands[seat.Index].Description));
							Thread.Sleep(2000);
						}
						else
						{
							m_ClosedCards[seat.Index] = null;
							Table.BroadCastMessage(string.Format("{0}: mucks hand", seat.Player.Login));
							Thread.Sleep(500);
						}
					}
				}

				while (!m_Pot.Empty && players.Count > 0)
				{
					Dictionary<string, double> winners = PokerHighHand.GetEquity(players, communitySet);
					int value = winners.Count;

					HashSet<string> split = new HashSet<string>();
					foreach (KeyValuePair<string, double> pair in winners)
						if (pair.Value != 0)
						{
							split.Add(pair.Key);
							players.Remove(pair.Key);
						}

					Dictionary<string, double> amountWon = m_Pot.GetWinnings(split);

					foreach (KeyValuePair<string, double> pair in amountWon)
					{
						PokerTableSeat seat = Table[pair.Key];
						if (seat == null)
							throw new NullReferenceException();
						seat.Stack += (ulong)pair.Value;
						m_Bets[seat.Index] = (ulong)pair.Value;
						Table.BroadCastMessage(string.Format("{0} collected {1} from the pot", seat.Player.Login, Currency.ToString((ulong)pair.Value)));
					}
					Thread.Sleep(1000);
				}
				if (!m_Pot.Empty)
					throw new Exception("money left in the pot.");
				Thread.Sleep(4000);
			}
			else if (playersLeft.Count == 1)
			{
				ulong totalAmount = m_Pot.TotalAmount;
				playersLeft[0].Stack += totalAmount;
				m_Bets[playersLeft[0].Index] += totalAmount;
				m_Pot = null;
				Table.BroadCastMessage(string.Format("{0} collected {1} from the pot", playersLeft[0].Player.Login, Currency.ToString(totalAmount)));
				m_CurrentAction = (byte)playersLeft[0].Index;
				if (GetShowCards(playersLeft[0], 2500))
				{
					CardSet communitySet = new CardSet(m_CommunityCards);
					CardSet set = new CardSet(m_ClosedCards[playersLeft[0].Index]);
					PokerHighHand hand = PokerHighHand.GetBestHand(new CardSet(set, communitySet));
					Visible.Add(m_ClosedCards[playersLeft[0].Index][0]);
					Visible.Add(m_ClosedCards[playersLeft[0].Index][1]);
					Table.BroadCastMessage(string.Format("{0}: won the pot ({1}) and shows [{2}] ({3}).", playersLeft[0].Player.Login, Currency.ToString(totalAmount), m_ClosedCards[playersLeft[0].Index], hand.Description));
				}
				else
					Table.BroadCastMessage(string.Format("{0}: doesn't show hand.", playersLeft[0].Player.Login, Currency.ToString(totalAmount)));
				Thread.Sleep(2000);
			}
			else
				throw new Exception("Internal error.");

			m_CurrentAction = 0xff;
			m_Pot = null;
			m_Deck = null;
			Visible.Clear();
			m_CommunityCards.Clear();
			for (int c = 0; c < m_ClosedCards.Length; c++)
				m_ClosedCards[c] = null;
			for (int c = 0; c < m_Bets.Length; c++)
				m_Bets[c] = 0;


			Table.Button = nextDealer;
			m_Busy = false;
			m_FirstHand = false;
			bool needEquilibrate = false;

			foreach (PokerTableSeat seat in Table.OccupiedSeats)
			{
				if (seat.State == PokerSeatState.Playing && seat.Stack == 0)
				{
					if (Configuration.IsTournament)
					{
						PokerTournamentConfiguration config = Configuration as PokerTournamentConfiguration;
						byte rebuyCount = 0;
						bool rebuyed = false;
						if (config.CanRebuy(seat.Player) && GetRebuy(seat, 6000, out rebuyCount))
						{
							rebuyCount = config.Rebuy(seat.Player, rebuyCount);
							if (rebuyCount > 0)
							{
								seat.Stack = (ulong)rebuyCount * config.RebuyChips;
								Table.BroadCastMessage(string.Format("{0}: rebuys {1} times and got {2}.", seat.Player.Login, rebuyCount, Currency.ToString((ulong)rebuyCount * config.RebuyChips)));
								rebuyed = true;
							}
						}
						if(!rebuyed)
						{
							PokerPlayer player = seat.Player;
							Table.Leave(seat.Index);
							uint position = config.Exit(player);
							needEquilibrate = config.IsMultiTable && !config.Finished;
							Table.BroadCastMessage(string.Format("{0}: leave the tournament finishing {1}.", player.Login, rebuyCount, position));
						}
					}
					else
					{
						seat.State = PokerSeatState.SittingOut;
						Table.BroadCastMessage(string.Format("{0}: sitting out.", seat.Player.Login));
					}
				}
				else if (seat.State == PokerSeatState.Disconnected)
				{
					if(Currency == seat.Player.Currency)
						seat.Player.BankRoll += seat.Stack;
					string login = seat.Player.Login;
					ulong stack = seat.Stack;
					seat.Player.RemoveSeat(seat);
					seat.State = PokerSeatState.Empty;
					seat.Player = null;
					seat.Stack = 0;
					Table.BroadCastMessage(string.Format("{0}: leaving with {1}.", login, Currency.ToString(stack)));
				}
			}
			if (needEquilibrate && Configuration.IsTournament)
			{
				PokerTournamentConfiguration config = Configuration as PokerTournamentConfiguration;
				config.EquilibrateTables();
			}
			//Table.BroadCastMessage(string.Format("Button goes to seat {0}.", nextDealer));
			Table.BroadCastInitTable();
		}

		private List<PokerTableSeat> OrderForShowdown(List<PokerTableSeat> playersLeft)
		{
			// the player are ordered based on their invested amount for equal amount the original order is conserved
			Dictionary<ulong, List<PokerTableSeat>> byAmount = new Dictionary<ulong, List<PokerTableSeat>>();
			for (int c = 0; c < playersLeft.Count; c++)
			{
				PokerTableSeat seat = playersLeft[c];
				ulong amount = m_Pot.GetTotalAmountForPlayer(seat.Player.Login);
				if (!byAmount.ContainsKey(amount))
					byAmount.Add(amount, new List<PokerTableSeat>());
				byAmount[amount].Add(seat);
			}
			List<ulong> sortedAmounts = new List<ulong>(byAmount.Keys);
			sortedAmounts.Sort(delegate(ulong a, ulong b) { return b.CompareTo(a); });
			List<PokerTableSeat> result = new List<PokerTableSeat>();
			foreach (ulong amount in sortedAmounts)
				result.AddRange(byAmount[amount]);
			return result;
		}

		protected List<PokerTableSeat> NextActions(List<PokerTableSeat> playersLeft, out bool allIn)
		{
			allIn = false;
			m_PlayersLeftToTalk = null;
			List<PokerTableSeat> notAllin = new List<PokerTableSeat>();
			foreach (PokerTableSeat seat in playersLeft)
				if (!seat.IsAllIn)
					notAllin.Add(seat);
			if (notAllin.Count < 2)
			{
				allIn = true;
				return playersLeft;
			}
			m_PlayersLeftToTalk = playersLeft;
			List<PokerTableSeat> playersReady = new List<PokerTableSeat>();
			while (playersLeft.Count > 0 && (playersLeft.Count > 1 || playersReady.Count > 0))
			{
				PokerTableSeat waiting = playersLeft[0];
				playersLeft.RemoveAt(0);
				if (waiting.IsAllIn)
					playersReady.Add(waiting);
				else
				{
					m_CurrentAction = (byte)waiting.Index;
					ulong amount = GetAmount(waiting, 20000);
					if(amount != ulong.MaxValue)
						amount = Math.Min(amount, waiting.Stack);
					ulong callAmount = m_Pot.GetCallAmountForPlayer(waiting.Player.Login);
					ulong minimumRaiseAmount = Math.Max(callAmount + BigBlind, callAmount * 2);
					PokerActionType actionType = PokerActionType.Fold;
					if (amount == ulong.MaxValue)
						amount = 0;
					else if (callAmount == 0 && amount == 0)
						actionType = PokerActionType.Check;
					else if (callAmount == amount || (amount < callAmount && amount == waiting.Stack))
						actionType = PokerActionType.Call;
					else if (amount >= minimumRaiseAmount || amount == waiting.Stack)
						actionType = PokerActionType.Raise;

					if (actionType == PokerActionType.Fold)
					{
						notAllin.Remove(waiting);
						m_ClosedCards[waiting.Index] = null;
						Table.BroadCastMessage(string.Format("{0}: folds", waiting.Player.Login));
						Table.BroadCastAction(waiting.Player.Login, PokerActionType.Fold, 0);
						continue;
					}
					else if (actionType == PokerActionType.Call || actionType == PokerActionType.Check)
						playersReady.Add(waiting);
					else if (actionType == PokerActionType.Raise)
					{
						playersLeft.AddRange(playersReady);
						playersReady.Clear();
						playersReady.Add(waiting);
					}
					m_Bets[waiting.Index] += amount;
					m_Pot.Add(waiting.Player.Login, amount);
					waiting.Stack -= amount;

					string message = "{0}: {1} {2}";
					if(waiting.IsAllIn)
						message = "{0}: {1} {2} and is all-in";
					if (amount == 0)
						message = message.Replace(" {2}", string.Empty);
					Table.BroadCastMessage(string.Format(message, waiting.Player.Login, actionType.ToString().ToLowerInvariant() + "s", Currency.ToString(amount)));
					Table.BroadCastAction(waiting.Player.Login, actionType, amount);

					if (waiting.IsAllIn)
						notAllin.Remove(waiting);

				}
			}
			List<PokerTableSeat> result = playersReady;
			if (playersReady.Count == 0)
				result = playersLeft;
			if (notAllin.Count < 2)
				allIn = true;
			foreach (PokerTableSeat seat in result)
			{
				//ulong amount = m_Pot.GetTotalAmountForPlayer(seat.Player.Login);
				ulong uncalledBet = m_Pot.UncalledBet(seat.Player.Login);
				if (uncalledBet > 0)
				{
					seat.Stack += uncalledBet;
					m_Pot.ReturnUncalledBet(seat.Player.Login, uncalledBet);
					m_Bets[seat.Index] -= uncalledBet;
					Table.BroadCastMessage(string.Format("Uncalled bet ({1}) returned to {0}", seat.Player.Login, Currency.ToString(uncalledBet)));
					Thread.Sleep(1000);
				}
			}
			m_CurrentAction = 0xff;
			return result;
		}

		protected bool GetRebuy(PokerTableSeat waiting, int timeOut, out byte rebuyCount)
		{
			rebuyCount = 0;
			if (waiting.Player.Socket != null)
			{
				if (waiting.State == PokerSeatState.Disconnected || (waiting.State == PokerSeatState.SittingOut && Configuration.IsTournament))
					return false;
				Table.BroadCastMessage(string.Format("{1} have {0} sec to rebuy.", timeOut / 1000, waiting.Player.Login));
				Table.BroadCastTimer(waiting.Index, timeOut);
				return waiting.Player.GetRebuy(Table, timeOut, out rebuyCount);
			}
			return rebuyCount != 0;
		}

		protected ulong GetAmount(PokerTableSeat waiting, int timeOut)
		{
			if (waiting.Player.Socket != null)
			{
				if (waiting.State == PokerSeatState.Disconnected || (waiting.State == PokerSeatState.SittingOut && Configuration.IsTournament))
					return 0;
				Table.BroadCastMessage(string.Format("{1} have {0} sec to act.", timeOut / 1000, waiting.Player.Login));
				Table.BroadCastTimer(waiting.Index, timeOut);
				ulong callAmount = m_Pot.GetCallAmountForPlayer(waiting.Player.Login);
				ulong minRaise = Math.Max(callAmount + BigBlind, callAmount * 2);
				return waiting.Player.GetAmount(Table, callAmount, minRaise, waiting.Stack, timeOut);
			}
			return 0;
		}

		protected bool GetShowCards(PokerTableSeat waiting, int timeOut)
		{
			if (waiting.Player.Socket != null)
			{
				if (waiting.State == PokerSeatState.Disconnected)
					return false;
				return waiting.Player.GetShowCards(Table, timeOut);
			}
			return false;
		}

		protected bool GetForcedPost(PokerTableSeat waiting, bool smallAndBig, int timeOut)
		{
			if (waiting.Player.Socket != null)
			{
				if (waiting.State == PokerSeatState.Disconnected)
					return false;
				Table.BroadCastMessage(string.Format("{1} have {0} sec to act.", timeOut / 1000, waiting.Player.Login));
				Table.BroadCastTimer(waiting.Index, timeOut);
				return waiting.Player.GetForcedPost(Table, smallAndBig, timeOut);
			}
			return false;
		}

		public override bool CanStartHand
		{
			get
			{
				if (m_Busy || Table.Closed)
					return false;
				List<PokerTableSeat> seats = new List<PokerTableSeat>(Table.OccupiedSeats);
				if (seats.Count < 2)
					return false;
				List<PokerTableSeat> playingSeats = new List<PokerTableSeat>();
				foreach (PokerTableSeat player in seats)
				{
					if ((player.State == Enums.PokerSeatState.Playing || player.State == Enums.PokerSeatState.Waiting) && player.Stack > 0)
						playingSeats.Add(player);
				}
				if (playingSeats.Count < 2)
					return false;
				return true;
			}
		}

		public override void Reset(Exception e)
		{
			m_Pot = null;
			m_Deck = null;
			Visible.Clear();
			m_CommunityCards.Clear();
			for (int c = 0; c < m_ClosedCards.Length; c++)
				m_ClosedCards[c] = null;
			for (int c = 0; c < m_Bets.Length; c++)
				m_Bets[c] = 0;
			m_Busy = false;


			foreach (PokerTableSeat player in Table.Seats)
			{
				if (player.State == PokerSeatState.Disconnected)
				{
					string login = player.Player.Login;
					player.Player.BankRoll += player.Stack;
					player.State = PokerSeatState.Empty;
					player.Player = null;
					player.Stack = 0;
					Table.BroadCastMessage(string.Format("{0}: leaving", login));
				}
			}
		}

		public override void PlayerShowCards(string playerName, CardList cards)
		{
			PokerTableSeat seat = Table[playerName];
			if (seat != null)
			{
				CardList closedCards = m_ClosedCards[seat.Index];
				if (closedCards != null)
				{
					CardList cardShown = new CardList();
					foreach (Card card in cards)
						if (closedCards.Contains(card) && !Visible.Contains(card))
						{
							Visible.Add(card);
							cardShown.Add(card);
						}
					if (cardShown.Count > 0)
					{
						Table.BroadCastMessage(string.Format("{0}: shows [{1}]", playerName, cardShown));
						Thread timer = new Thread(delegate()
						{
							Thread.Sleep(2000);
							foreach (Card card in cardShown)
								Visible.Remove(card);
							Table.BroadCastInitTable();
						});
						timer.Start();
					}
				}
			}
		}

	}
}
